{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 项目源地址： https://gitee.com/research-project-team/Handwritten_Mathematical_Calculator_on_FPGA\n",
    "# 进行参考\n",
    "#==================================================\n",
    "#                import package\n",
    "#=================================================\n",
    "import math\n",
    "from pynq import Overlay\n",
    "import numpy as np\n",
    "from PIL import Image as PIL_Image\n",
    "from pynq import MMIO\n",
    "from pynq import allocate   \n",
    "import time\n",
    "import datetime\n",
    "import ctypes\n",
    "import cv2\n",
    "import os\n",
    "import queue\n",
    "import re\n",
    "import sys"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "#==================================================\n",
    "#                Image Input Path\n",
    "#=================================================\n",
    "img_path = \"./test_1.jpeg\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "#==================================================\n",
    "#                Load overlay  and IP\n",
    "#=================================================\n",
    "overlay = Overlay(\"./handwritten.bit\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "load....\n"
     ]
    }
   ],
   "source": [
    "print(\"load....\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Weight: 16M 449839104\n",
      "Bias: 4K 377937920\n",
      "Img: 52K 378077184\n"
     ]
    }
   ],
   "source": [
    "#==================================================\n",
    "#            allocated the memory  inbuff\n",
    "#=================================================\n",
    "weight_base_buffer = allocate(shape=(4260640,), dtype=np.int32)\n",
    "print(\"Weight: 16M\",weight_base_buffer.physical_address)\n",
    "WEIGHT_BASE = weight_base_buffer.physical_address\n",
    "\n",
    "beta_base_buffer = allocate(shape=(1134,), dtype=np.int32)\n",
    "print(\"Bias: 4K\",beta_base_buffer.physical_address)\n",
    "BETA_BASE=beta_base_buffer.physical_address\n",
    "\n",
    "img_base_buffer = allocate(shape=(13312,), dtype=np.int32)\n",
    "print(\"Img: 52K\",img_base_buffer.physical_address)\n",
    "IMG_MEM = img_base_buffer.physical_address\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Weight copy ok\n",
      "Bias copy ok\n"
     ]
    }
   ],
   "source": [
    "#===============================================\n",
    "#        weight and bais copyto memory\n",
    "#==============================================\n",
    "params_wight = np.fromfile(\"./weight.bin\", dtype=np.int32)\n",
    "np.copyto(weight_base_buffer, params_wight)\n",
    "print(\"Weight copy ok\")\n",
    "\n",
    "params_bais = np.fromfile(\"./bias.bin\", dtype=np.int32)\n",
    "np.copyto(beta_base_buffer, params_bais)\n",
    "print(\"Bias copy ok\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "#===============================================\n",
    "#                network data\n",
    "#==============================================\n",
    "weight_offset = [800, 51200, 4194304]\n",
    "beta_offset = [32, 64, 1024]\n",
    "M_value = [94, 48, 43]\n",
    "\n",
    "K=5\n",
    "Tn=4\n",
    "Tm=32\n",
    "Tr=32\n",
    "Tc=32\n",
    "ALPHA_BETA_MAX_NUM=1024\n",
    "\n",
    "SIZE = 32\n",
    "\n",
    "SYMBOL = {0: '0',\n",
    "          1: '1',\n",
    "          2: '2',\n",
    "          3: '3',\n",
    "          4: '4',\n",
    "          5: '5',\n",
    "          6: '6',\n",
    "          7: '7',\n",
    "          8: '8',\n",
    "          9: '9',\n",
    "          10: '+',\n",
    "          11: '-',\n",
    "          12: '*',\n",
    "          13: '/'}\n",
    "\n",
    "SCALE = 0.007874015748031496\n",
    "\n",
    "MEM_BASE = IMG_MEM\n",
    "MEM_LEN = 16*16*32*4 + 8*8*64*4\n",
    "Memory_top = MEM_BASE\n",
    "Memory_bottom = MEM_BASE + MEM_LEN\n",
    "\n",
    "in_ptr  = np.zeros(4)\n",
    "out_ptr = np.zeros(4)\n",
    "\n",
    "in_ptr[0] = Memory_top\n",
    "out_ptr[0] = Memory_bottom - 16*16*32*4\n",
    "\n",
    "in_ptr[1] = out_ptr[0]\n",
    "out_ptr[1] = Memory_top\n",
    "\n",
    "in_ptr[2] = out_ptr[1]\n",
    "out_ptr[2] = Memory_bottom - 1024*4\n",
    "\n",
    "in_ptr[3] = out_ptr[2]\n",
    "out_ptr[3] = Memory_top"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "#===============================================\n",
    "#              image pre-processing\n",
    "#==============================================\n",
    "def quantized_np(array,scale,data_width=8):\n",
    "    \"\"\"Quantify the input data of network,\n",
    "    Args:\n",
    "        array: input image data array. In this project its shape is [1,32*32].\n",
    "        scale: Quantized parameter. Calculate offline.\n",
    "        data_width: Quantized parameter. Define the quantization accuracy.\n",
    "    Returns：\n",
    "        quantized array\n",
    "    \"\"\"\n",
    "    quantized_array= np.round(array/scale)\n",
    "    quantized_array = np.maximum(quantized_array, -2**(data_width-1))\n",
    "    quantized_array = np.minimum(quantized_array, 2**(data_width-1)-1)\n",
    "    return quantized_array\n",
    "\n",
    "def get_x_y_cuts(data, n_lines=1):\n",
    "    \"\"\"Find and put the similar pixels in a array.\n",
    "    Args:\n",
    "        data: image pixels data, 2-D array.\n",
    "        n_lines: line of number. we use 1 line data ONLY.\n",
    "    Returns:\n",
    "        a list which single element is the axis range.\n",
    "   \"\"\"\n",
    "    w, h = data.shape\n",
    "    visited = set()\n",
    "    q = queue.Queue()\n",
    "    offset = [(-1, -1), (0, -1), (1, -1), (-1, 0),\n",
    "              (1, 0), (-1, 1), (0, 1), (1, 1)]\n",
    "    cuts = []\n",
    "    for y in range(h):\n",
    "        for x in range(w):\n",
    "            x_axis = []\n",
    "            y_axis = []\n",
    "            if data[x][y] < 200 and (x, y) not in visited:\n",
    "                q.put((x, y))\n",
    "                visited.add((x, y))\n",
    "            while not q.empty():\n",
    "                x_p, y_p = q.get()\n",
    "                for x_offset, y_offset in offset:\n",
    "                    x_c, y_c = x_p + x_offset, y_p + y_offset\n",
    "                    if (x_c, y_c) in visited:\n",
    "                        continue\n",
    "                    visited.add((x_c, y_c))\n",
    "                    try:\n",
    "                        if data[x_c][y_c] < 200:\n",
    "                            q.put((x_c, y_c))\n",
    "                            x_axis.append(x_c)\n",
    "                            y_axis.append(y_c)\n",
    "                    except:\n",
    "                        pass\n",
    "            if x_axis:\n",
    "                min_x, max_x = min(x_axis), max(x_axis)\n",
    "                min_y, max_y = min(y_axis), max(y_axis)\n",
    "                if max_x - min_x > 3 and max_y - min_y > 3:\n",
    "                    cuts.append([min_x, max_x + 1, min_y, max_y + 1])\n",
    "    if n_lines == 1:\n",
    "        cuts = sorted(cuts, key=lambda x: x[2])\n",
    "        pr_item = cuts[0]\n",
    "        count = 1\n",
    "        len_cuts = len(cuts)\n",
    "        new_cuts = [cuts[0]]\n",
    "        pr_k = 0\n",
    "        for i in range(1, len_cuts):\n",
    "            pr_item = new_cuts[pr_k]\n",
    "            now_item = cuts[i]\n",
    "            if not (now_item[2] > pr_item[3]):\n",
    "                new_cuts[pr_k][0] = min(pr_item[0], now_item[0])\n",
    "                new_cuts[pr_k][1] = max(pr_item[1], now_item[1])\n",
    "                new_cuts[pr_k][2] = min(pr_item[2], now_item[2])\n",
    "                new_cuts[pr_k][3] = max(pr_item[3], now_item[3])\n",
    "            else:\n",
    "                new_cuts.append(now_item)\n",
    "                pr_k += 1\n",
    "        cuts = new_cuts\n",
    "    return cuts\n",
    "\n",
    "def get_image_cuts(image, dir=None, is_data=False, n_lines=1, data_needed=False, count=0,QUAN = False):\n",
    "    \"\"\"Cut the image, find relevant small pieces.\n",
    "    Args:\n",
    "        image: can input image or pixel array.\n",
    "        dir: the small pieces image save dir.\n",
    "        is_data: decide the type of input image.\n",
    "        data_needed: decide whether to return pixel array.\n",
    "        count: the number of small pieces \n",
    "        QUAN: decide whether to quantify\n",
    "    Returns:\n",
    "        the number of small pieces image(for Debug) or\n",
    "        small pieces image pixel array\n",
    "    \"\"\" \n",
    "    \n",
    "    if is_data:\n",
    "        data = image\n",
    "    else:\n",
    "        data = cv2.imread(image, 2)\n",
    "    cuts = get_x_y_cuts(data, n_lines=n_lines)\n",
    "    image_cuts = None\n",
    "    for i, item in enumerate(cuts):\n",
    "        count += 1\n",
    "        max_dim = max(item[1] - item[0], item[3] - item[2])\n",
    "        new_data = np.ones((int(1.4 * max_dim), int(1.4 * max_dim))) * 255\n",
    "        x_min, x_max = (\n",
    "            max_dim - item[1] + item[0]) // 2, (max_dim - item[1] + item[0]) // 2 + item[1] - item[0]\n",
    "        y_min, y_max = (\n",
    "            max_dim - item[3] + item[2]) // 2, (max_dim - item[3] + item[2]) // 2 + item[3] - item[2]\n",
    "        new_data[int(0.2 * max_dim) + x_min:int(0.2 * max_dim) + x_max, int(0.2 * max_dim) +\n",
    "                 y_min:int(0.2 * max_dim) + y_max] = data[item[0]:item[1], item[2]:item[3]]\n",
    "\n",
    "        standard_data = cv2.resize(new_data, (SIZE, SIZE))\n",
    "        cv2.imwrite(dir + str(count) + \".jpg\", standard_data)\n",
    "        if not data_needed:\n",
    "            cv2.imwrite(dir + str(count) + \".jpg\", standard_data)\n",
    "        if data_needed:\n",
    "            data_flat = np.reshape(standard_data, (1, SIZE*SIZE))\n",
    "            data_flat = (255 - data_flat) / 255\n",
    "\n",
    "            if QUAN == True:\n",
    "                data_flat = quantized_np(data_flat,SCALE,data_width=8)\n",
    "            else:\n",
    "                pass\n",
    "            \n",
    "            if image_cuts is None:\n",
    "                image_cuts = data_flat\n",
    "            else:\n",
    "                image_cuts = np.r_[image_cuts, data_flat]\n",
    "    if data_needed:\n",
    "        return image_cuts\n",
    "    return count\n",
    "\n",
    "def image_cut(quan):\n",
    "    \"\"\"Get a image and use get_image_cuts function pre-process it\n",
    "    Args:\n",
    "        quan: decide whether to quantify\n",
    "    Returns:\n",
    "        small image pixel array\n",
    "    \"\"\"\n",
    "    # print(\"Please enter image source:\")\n",
    "    # mode = input(\"C(camera) or F(file)\") or \"F\"\n",
    "    mode = \"F\" # the defualt input image source\n",
    "    if mode == \"C\":\n",
    "        cap = cv2.VideoCapture(0) \n",
    "        _ , img = cap.read()\n",
    "    elif mode == \"F\":\n",
    "        img = cv2.imread(img_path, 2)\n",
    "    else:\n",
    "        print(\"Illegal source! Please run program again\")\n",
    "        sys.exit()\n",
    "    image_cuts = get_image_cuts(\n",
    "        img, dir=\"./img_cut_results/cut\", is_data=True, count=0, data_needed=True, QUAN=quan)\n",
    "    return image_cuts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "#===============================================\n",
    "#                 hw init\n",
    "#==============================================\n",
    "#IP_base_address\n",
    "IP_BASE_ADDRESS    =  0x43C00000\n",
    "ADDRESS_RANGE      = 0x180\n",
    "\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_AP_CTRL            =0x00\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_GIE                =0x04\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_IER                =0x08\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_ISR                =0x0c\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_INPUT_OFFSET_DATA  =0x10\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_OUTPUT_OFFSET_DATA =0x18\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_WEIGHT_OFFSET_DATA =0x20\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_BETA_OFFSET_DATA   =0x28\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_INFM_NUM_DATA      =0x30\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_OUTFM_NUM_DATA     =0x38\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_KERNEL_SIZE_DATA   =0x40\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_KERNEL_STRIDE_DATA =0x48\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_TM_DATA            =0x50\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_TN_DATA            =0x58\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_TR_DATA            =0x60\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_TC_DATA            =0x68\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_MLOOPS_DATA        =0x70\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_NLOOPS_DATA        =0x78\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_LAYERTYPE_DATA     =0x80\n",
    "XDETECTION_ACC_CRTL_BUS_ADDR_M_DATA             =0x88\n",
    "\n",
    "def HMC_Init_EX(In_Address,Out_Address,Weight_offset,Beta_offset,InFM_num,OutFM_num,\n",
    "                 Kernel_size,Kernel_stride,\n",
    "                 TM,TN,TR,TC,\n",
    "                 mLoops,nLoops,LayerType,\n",
    "                 WEIGHT_BASE,BETA_BASE,M):\n",
    "   \n",
    "    # mapping memory\n",
    "    mmio = MMIO(IP_BASE_ADDRESS,ADDRESS_RANGE)\n",
    "    \n",
    "    while True:\n",
    "        ap_idle =  (mmio.read(XDETECTION_ACC_CRTL_BUS_ADDR_AP_CTRL)>>2)&0x01\n",
    "        if(ap_idle):\n",
    "            break\n",
    "    \n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_INPUT_OFFSET_DATA,  In_Address)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_OUTPUT_OFFSET_DATA, Out_Address)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_WEIGHT_OFFSET_DATA, WEIGHT_BASE+Weight_offset*4)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_BETA_OFFSET_DATA,   BETA_BASE+Beta_offset*4)\n",
    "\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_INFM_NUM_DATA,      InFM_num)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_OUTFM_NUM_DATA,     OutFM_num)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_KERNEL_SIZE_DATA,   Kernel_size)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_KERNEL_STRIDE_DATA, Kernel_stride)\n",
    "\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_TM_DATA,        TM)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_TN_DATA,        TN)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_TR_DATA,        TR)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_TC_DATA,        TC)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_MLOOPS_DATA,    mLoops)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_NLOOPS_DATA,    nLoops)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_LAYERTYPE_DATA, LayerType)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_M_DATA,         M)\n",
    "\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_GIE,    0)\n",
    "    mmio.write(XDETECTION_ACC_CRTL_BUS_ADDR_AP_CTRL,1)\n",
    "    while True:\n",
    "        ap_done =  (mmio.read(XDETECTION_ACC_CRTL_BUS_ADDR_AP_CTRL)>>1)&0x01\n",
    "        if(ap_done):\n",
    "            break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "#==============================================\n",
    "#                  hw  control\n",
    "#==============================================\n",
    "def calculator_ps(img_base_buffer):\n",
    "         \n",
    "    TR=0\n",
    "    TC=0\n",
    "    TM=0\n",
    "    TN=0\n",
    "    offset_index=0\n",
    "    woffset = 0\n",
    "    boffset = 0\n",
    "\n",
    "    img_reorg_buffer = np.zeros((64, 8, 8), dtype=np.int32)\n",
    "\n",
    "    for i in range(0,4):\n",
    "       \n",
    "        if i == 0:\n",
    "\n",
    "            TR = 32\n",
    "            TC = 32\n",
    "            TM = 32\n",
    "            TN = 1\n",
    "\n",
    "            mLoops = 1\n",
    "            nLoops = 1\n",
    "    \n",
    "            start_time = time.time()\n",
    "            HMC_Init_EX(int(in_ptr[i]),int(out_ptr[i]),woffset,boffset,1,32,\n",
    "                5,1,TM,TN,TR,TC,mLoops,nLoops,0,\n",
    "                WEIGHT_BASE,BETA_BASE,M_value[0])\n",
    "            end_time = time.time()\n",
    "            # print(\"Conv0 time:\", end_time - start_time)\n",
    "\n",
    "            woffset += weight_offset[offset_index]\n",
    "            boffset += beta_offset[offset_index]  \n",
    "            offset_index = offset_index+1\n",
    "\n",
    "        elif i == 1:\n",
    "\n",
    "            TR = 16\n",
    "            TC = 16\n",
    "            TM = 32\n",
    "            TN = 4\n",
    "\n",
    "            mLoops = 2\n",
    "            nLoops = 8\n",
    "\n",
    "            start_time = time.time()\n",
    "            HMC_Init_EX(int(in_ptr[i]),int(out_ptr[i]),woffset,boffset,32,64,\n",
    "                        5,1,TM,TN,TR,TC,mLoops,nLoops,0,\n",
    "                        WEIGHT_BASE,BETA_BASE,M_value[1])\n",
    "            end_time = time.time()\n",
    "            # print(\"Conv2 time:\", end_time - start_time)\n",
    "            \n",
    "            woffset += weight_offset[offset_index]\n",
    "            boffset += beta_offset[offset_index]  \n",
    "            offset_index = offset_index+1\n",
    "\n",
    "        elif i == 2:\n",
    "\n",
    "            for m in range(0, 64):\n",
    "                for r in range(0, 8):\n",
    "                    for c in range(0, 8):\n",
    "                        img_reorg_buffer[m][r][c] = img_base_buffer[m * 64 + r * 8 + c]\n",
    "\n",
    "            for r in range(0, 8):\n",
    "                for c in range(0, 8):\n",
    "                    for m in range(0, 64):\n",
    "                        img_base_buffer[r * 512 + c * 64 + m] = img_reorg_buffer[m][r][c]\n",
    "\n",
    "            TR = 1\n",
    "            TC = 1\n",
    "            TM = 32\n",
    "            TN = 4\n",
    "            mLoops = 1024\n",
    "            nLoops = 1\n",
    "\n",
    "            start_time = time.time()\n",
    "            HMC_Init_EX(int(in_ptr[i]),int(out_ptr[i]),woffset,boffset,8*8*64,1024,\n",
    "                        1,1,TM,TN,TR,TC,mLoops,nLoops,1,\n",
    "                        WEIGHT_BASE,BETA_BASE,M_value[2])\n",
    "            end_time = time.time()\n",
    "            # print(\"FC4 time:\", end_time - start_time)\n",
    "\n",
    "        elif i == 3:\n",
    "\n",
    "            start_time = time.time()\n",
    "            for m in range(0,14):\n",
    "                for n in range(0,1024):\n",
    "                    if n==0:\n",
    "                        tmp_add_result = beta_base_buffer[1120 + m]\n",
    "                    else:\n",
    "                        tmp_add_result = img_base_buffer[m]\n",
    "                    \n",
    "                    partial_mul = img_base_buffer[11264+n]*weight_base_buffer[4246304 + m * 1024 + n]\n",
    "\n",
    "                    img_base_buffer[m] = partial_mul + tmp_add_result\n",
    "\n",
    "                # print(m, img_base_buffer[m])\n",
    "            \n",
    "            end_time = time.time()\n",
    "            # print(\"FC5 time:\", end_time - start_time)\n",
    "    print(\"FPGA_Accelerate_Completed!!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [],
   "source": [
    "#===============================================\n",
    "#                calculator\n",
    "#==============================================\n",
    "def md(l, x):\n",
    "    \"\"\"Multiplication and division.\n",
    "    Args:\n",
    "        l: String\n",
    "        x: Operator\n",
    "    Returns:\n",
    "        a string which insert calculator result\n",
    "    \"\"\"\n",
    "    a = l.index(x)\n",
    "    if x == '*' and l[a + 1] != '-':\n",
    "        k = float(l[a - 1]) * float(l[a + 1])\n",
    "    elif x == '/' and l[a + 1] != '-':\n",
    "        k = float(l[a - 1]) / float(l[a + 1])\n",
    "    elif x == '*' and l[a + 1] == '-':\n",
    "        k = -(float(l[a - 1]) * float(l[a + 2]))\n",
    "    elif x == '/' and l[a + 1] == '-':\n",
    "        k = -(float(l[a - 1]) / float(l[a + 2]))\n",
    "    del l[a - 1], l[a - 1], l[a - 1]\n",
    "    l.insert(a - 1, str(k))\n",
    "    return l\n",
    "\n",
    "def calculator(formula):\n",
    "    \"\"\"Calculator main function\n",
    "    Args:\n",
    "        formula: a string.\n",
    "    Returns:\n",
    "        Calculator result.\n",
    "    \n",
    "    \"\"\"\n",
    "    l = re.findall('([\\d\\.]+|/|-|\\+|\\*)', formula)\n",
    "    sum = 0\n",
    "    while 1:\n",
    "        if '*' in l and '/' not in l:\n",
    "            md(l, '*')\n",
    "        elif '*' not in l and '/' in l:\n",
    "            md(l, '/')\n",
    "        elif '*' in l and '/' in l:\n",
    "            a = l.index('*')\n",
    "            b = l.index('/')\n",
    "            if a < b:\n",
    "                md(l, '*')\n",
    "            else:\n",
    "                md(l, '/')\n",
    "        else:\n",
    "            if l[0] == '-':\n",
    "                l[0] = l[0] + l[1]\n",
    "                del l[1]\n",
    "            sum += float(l[0])\n",
    "            for i in range(1, len(l), 2):\n",
    "                if l[i] == '+' and l[i + 1] != '-':\n",
    "                    sum += float(l[i + 1])\n",
    "                elif l[i] == '+' and l[i + 1] == '-':\n",
    "                    sum -= float(l[i + 2])\n",
    "                elif l[i] == '-' and l[i + 1] == '-':\n",
    "                    sum += float(l[i + 2])\n",
    "                elif l[i] == '-' and l[i + 1] != '-':\n",
    "                    sum -= float(l[i + 1])\n",
    "            break\n",
    "    return sum"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [],
   "source": [
    "#==============================================\n",
    "#                 main function\n",
    "#==============================================\n",
    "def main():\n",
    "    \n",
    "    img = image_cut(quan=True)\n",
    "\n",
    "    formula = ''\n",
    "    print(\"Charactor Number is:\", np.size(img, 0))\n",
    "    for i in range(np.size(img, 0)):\n",
    "        '''\n",
    "        index = inference(img[i])\n",
    "        '''\n",
    "        np.copyto(img_base_buffer[0:1024], img[i].astype(np.int32))\n",
    "        print(\"Detect the Number:\", i+1)\n",
    "        calculator_ps(img_base_buffer)\n",
    "        print(\"Detect Successfully!\")\n",
    "        index = np.argmax(img_base_buffer[0:14], 0)\n",
    "        formula += SYMBOL[index]\n",
    "    print(\"The Handwritten Mathematical Expression is:\", formula)\n",
    "    print(\"Begin to Calculate the Result!\")\n",
    "    result = calculator(formula)\n",
    "    print(\"The Result is:\", result)\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Charactor Number is: 5\n",
      "Detect the Number: 1\n",
      "FPGA_Accelerate_Completed!!\n",
      "Detect Successfully!\n",
      "Detect the Number: 2\n",
      "FPGA_Accelerate_Completed!!\n",
      "Detect Successfully!\n",
      "Detect the Number: 3\n",
      "FPGA_Accelerate_Completed!!\n",
      "Detect Successfully!\n",
      "Detect the Number: 4\n",
      "FPGA_Accelerate_Completed!!\n",
      "Detect Successfully!\n",
      "Detect the Number: 5\n",
      "FPGA_Accelerate_Completed!!\n",
      "Detect Successfully!\n",
      "The Handwritten Mathematical Expression is: 1+2/4\n",
      "Begin to Calculate the Result!\n",
      "The Result is: 1.5\n"
     ]
    }
   ],
   "source": [
    "#==============================================\n",
    "#                 start detection\n",
    "#==============================================\n",
    "main()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "##============================================\n",
    "#                 clean  up\n",
    "#============================================\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
